package cn.wildfirechat.app.aop;

import cn.wildfirechat.app.RestResult;
import cn.wildfirechat.app.jpa.LoginLog;
import cn.wildfirechat.app.jpa.LoginLogRepository;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputOutputUserInfo;
import cn.wildfirechat.sdk.UserAdmin;
import cn.wildfirechat.sdk.model.IMResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

@Aspect
@Component
public class LoginLogAspect {
    private static final Logger LOG = LoggerFactory.getLogger(LoginLogAspect.class);

    @Autowired
    private LoginLogRepository loginLogRepository;

    @Around("execution(* cn.wildfirechat.app.ServiceImpl.loginWithMobileCode(..)) || execution(* cn.wildfirechat.app.ServiceImpl.loginWithPassword(..))")
    public Object logLoginAround(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        String mobile = safeArg(args, 1);
        String clientId = safeArg(args, 3);
        Integer platform = safeIntArg(args, 4);

        RestResult result;
        boolean success = false;
        try {
            Object proceed = pjp.proceed();
            if (proceed instanceof RestResult) {
                result = (RestResult) proceed;
                success = result.getCode() == RestResult.RestCode.SUCCESS.code;
            } else {
                // 非预期返回类型，当作失败
                result = RestResult.error(RestResult.RestCode.ERROR_SERVER_ERROR);
            }
        } catch (Throwable t) {
            // 执行异常记录失败日志后抛出
            recordLoginLog(mobile, null, null, clientId, platform, false);
            throw t;
        }

        // 填充用户信息
        String userId = null;
        String userName = null;
        try {
            if (!StringUtils.isEmpty(mobile)) {
                IMResult<InputOutputUserInfo> userResult = UserAdmin.getUserByMobile(mobile);
                if (userResult != null && userResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && userResult.getResult() != null) {
                    userId = userResult.getResult().getUserId();
                    userName = userResult.getResult().getDisplayName();
                }
            }
        } catch (Exception e) {
            LOG.warn("Fetch user info for login log failed", e);
        }

        recordLoginLog(mobile, userId, userName, clientId, platform, success);
        return result;
    }

    private String safeArg(Object[] args, int index) {
        if (args != null && args.length > index && args[index] instanceof String) {
            return (String) args[index];
        }
        return null;
    }

    private Integer safeIntArg(Object[] args, int index) {
        if (args != null && args.length > index) {
            Object o = args[index];
            if (o instanceof Integer) {
                return (Integer) o;
            }
        }
        return null;
    }

    private String getIp() {
        try {
            ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attrs != null) {
                String xff = attrs.getRequest().getHeader("X-Forwarded-For");
                String rip = attrs.getRequest().getHeader("X-Real-IP");
                String ip = attrs.getRequest().getRemoteAddr();
                if (!StringUtils.isEmpty(xff)) {
                    return xff.split(",")[0].trim();
                } else if (!StringUtils.isEmpty(rip)) {
                    return rip;
                }
                return ip;
            }
        } catch (Exception ignore) {
        }
        return null;
    }

    private Integer getRemotePort() {
        try {
            ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attrs != null) {
                return attrs.getRequest().getRemotePort();
            }
        } catch (Exception ignore) {
        }
        return null;
    }

    private void recordLoginLog(String mobile, String userId, String userName, String clientId, Integer platform, boolean success) {
        try {
            LoginLog log = new LoginLog();
            log.setMobile(mobile);
            log.setUserId(userId);
            log.setUserName(userName);
            log.setIp(getIp());
            log.setPort(getRemotePort());
            log.setLoginTime(new Date());
            log.setClientId(clientId);
            if (platform != null) {
                log.setPlatform(platform);
            }
            log.setSuccess(success);
            loginLogRepository.save(log);
        } catch (Exception e) {
            LOG.warn("recordLoginLog failed", e);
        }
    }
}
